package com.yangyang.ralearn.net.frame;

import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
import org.jboss.netty.handler.codec.replay.VoidEnum;

import com.yangyang.ralearn.net.message.AbstractMessage;
import com.yangyang.ralearn.net.message.MessageFactory;
import com.yangyang.ralearn.net.serialize.SerializeEntity;

/**
 * 帧解析器
 * 
 * @author yangyang
 * 
 */
public class FrameDecoder extends ReplayingDecoder<VoidEnum> {

	/**
	 * 每一帧的头部，做帧分隔和校验用
	 */
	public final static byte[] FrameHeader = { 1, 2, 3, 4 };
	public final static int BUFFER_SIZE = 10240;
	private FrameStatusEnum status = FrameStatusEnum.INIT;
	private byte[] buffer = new byte[BUFFER_SIZE]; // 内存缓冲数组，最大长度
	private int contentSize;// 当前帧的主体大小

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	protected Object decode(ChannelHandlerContext arg0, Channel arg1,
			ChannelBuffer arg2, VoidEnum arg3) throws Exception {
		// TODO Auto-generated method stub
		switch (status) {
		case INIT:
		case READING_HEADER:
		case FINISH:
			if (arg2.readableBytes() < FrameHeader.length) {
				status = FrameStatusEnum.READING_HEADER;
				break;
			} else {
				arg2.readBytes(buffer, 0, FrameHeader.length);
				for (int i = 0; i < FrameHeader.length; i++) {
					if (buffer[i] != FrameHeader[i]) {
						status = FrameStatusEnum.ERROR;
						break;
					}
				}
				if (status != FrameStatusEnum.ERROR) {
					contentSize = arg2.readInt();
					if (contentSize < 0 || contentSize > BUFFER_SIZE) {
						status = FrameStatusEnum.ERROR;
					} else
						status = FrameStatusEnum.READING_BODY;
				}
			}
		case READING_BODY:
			if (arg2.readableBytes() >= contentSize) {
				status = FrameStatusEnum.FINISH;
				int messageId = arg2.readInt();
				// Logger.getLogger(FrameDecoder.class).debug(
				// "recieve message id : " + messageId);
				arg2.readBytes(buffer, 0, contentSize - 4);
				AbstractMessage message = MessageFactory.instance()
						.createMessage(messageId);
				if (message != null)
					SerializeEntity.deserialize(message, buffer,
							(Integer[]) null);
				// arg2.discardReadBytes();
				return message;
			} else {
				break;
			}
		case ERROR:
			Logger.getLogger(FrameDecoder.class).error("decode error!");
			break;
		}
		Logger.getLogger(FrameDecoder.class).debug("status:" + status);
		return null;
	}

	public static void encode(ChannelBuffer buffer, AbstractMessage message,
			Integer... writable) {
		buffer.writeBytes(FrameHeader);
		int index = buffer.readableBytes();
		buffer.writeInt(0);
		buffer.writeInt(message.getId());
		SerializeEntity.serialize(buffer, message, writable);
		buffer.setInt(index, buffer.readableBytes() - index - 4);
	}

	public static ChannelBuffer encode(AbstractMessage message,
			Integer... writable) {
		ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
		encode(buffer, message, writable);
		return buffer;
	}
}
